<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <meta name="HandheldFriendly" content="true"/>

        <link rel="apple-touch-icon" sizes="180x180" href="./doc/favicon/apple-touch-icon.png">
        <link rel="icon" type="image/png" sizes="32x32" href="./doc/favicon/32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="./doc/favicon/16x16.png">
        <link rel="manifest" href="./doc/favicon/site.webmanifest">

        <title>Cotonic</title>

        <style>
body {
    background: #f4f4f4;
    color: #000;
    font-family: sans-serif;
}

section#sidebar {
    background: #fff;
    position: fixed;

    top: 0; left: 0; bottom: 0;
    width: 200px;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    padding: 15px 0 30px 30px;
    border-right: 1px solid #bbb;
    box-shadow: 0 0 20px #ccc; 
}

section#documentation {
    width: 550px;
    margin: 40px 0 50px 260px;
}

h1.logo {
    color: #0778B0;
    font-size: 48px;
    padding-top: 0px;
}

a.toc_title, a.toc_title:visited {
    display: block;
    color: #0778B0;
    font-weight: bold;
    margin-top: 15px;
}

ul.toc_section {
    font-size: small;
    line-height: 100%;
    margin: 5px 0 0 0;
    padding-left: 0px;
    list-style-type: none;
}

ul.toc_section ul {
    padding-top: 0.66ex; 
    padding-left: 2em;
    list-style-type: none;
}

.toc_section li {
    cursor: pointer;
    margin: 0 0 3px 0;
}
.toc_section li a {
    text-decoration: none;
    color: black;
}
.toc_section li a:hover {
    text-decoration: underline;
}

h1, h2, h3, h4, h5, h6 {
    padding-top: 20px;
}

strong.header {
    color: #0778B0;
    font-weight: bolder;
    line-height: 200%;
}

code {
    margin-left: 20px;
}

pre {
    padding: 2px 0 2px 15px;
    border-left: 5px solid #bbb;
    margin: 0px 0 30px;
}

.note {
    border: 1px solid #ee8;
    background-color: #ffc;
    padding: 0 10px;
    color: #333;
}

@media only screen and (-webkit-min-device-pixel-ratio: 1.5) and (max-width: 640px),
       only screen and (-o-min-device-pixel-ratio: 3/2) and (max-width: 640px),
       only screen and (min-device-pixel-ratio: 1.5) and (max-width: 640px) {

    section#sidebar {
        -webkit-overflow-scrolling: initial;
        position: relative;
        width: 90%;
        height: 120px;
        left: 0;
        top: -7px;
        padding: 10px 0 10px 30px;
        border: 0;
    }

    section#documentation {
        margin: 0;
        width: 100%;
    }

    pre {
        overflow: auto;
    }
}

        </style>
    </head>
    <body>
        <section id="sidebar">
            <div>
                <a class="toc_title" href="#">
                    Cotonic <span class="version">(1.0.3)</span>
                </a>

                <ul class="toc_section">
                    <li>&raquo; <a href="https://github.com/cotonic/cotonic">Github Repository</a></li>
                    <li>&raquo; <a href="#">Introduction</a></li>
                    <li>&raquo; <a href="#workers">Workers</a></li>
                </ul>

                <a class="toc_title" href="#functions">
                    Page Functions
                </a>
                <ul class="toc_section">
                    <li> - <a href="#cotonic.spawn">spawn</a>
                    <li> - <a href="#cotonic.spawn_named">spawn_named</a>
                    <li> - <a href="#cotonic.exit">exit</a>
                    <li> - <a href="#cotonic.send">send</a>
                    <li> - <a href="#cotonic.receive">receive</a>
                    <li> - <a href="#cotonic.set_worker_base_src">set_worker_base_src</a>
                </ul>

                <!-- Broker -->
                <a href="#cotonic.broker" class="toc_title">
                    broker
                </a>

                <ul class="toc_section">
                     <li> - <a href="#cotonic.broker.find_subscriptions_below">find_subscriptions_below</a>
                     <li> - <a href="#cotonic.broker.match">match</a>
                     <li> - <a href="#cotonic.broker.publish">publish</a>
                     <li> - <a href="#cotonic.broker.subscribe">subscribe</a>
                     <li> - <a href="#cotonic.broker.unsubscribe">unsubscribe</a>
                     <li> - <a href="#cotonic.broker.call">call</a>
                </ul>

                <!-- MQTT -->
                <a href="#cotonic.mqtt" class="toc_title">
                    mqtt
                </a>
                <ul class="toc_section">
                    <li> - <a href="#cotonic.mqtt.matches">matches</a>
                    <li> - <a href="#cotonic.mqtt.fill">fill</a>
                    <li> - <a href="#cotonic.mqtt.extract">extract</a>
                    <li> - <a href="#cotonic.mqtt.exec">exec</a>
                    <li> - <a href="#cotonic.mqtt.remove_named_wildcards">remove_named_wildcards</a>
                </ul>

                <!-- MQTT Bridge -->
                <a href="#cotonic.mqtt_bridge" class="toc_title">
                    mqtt_bridge
                </a>
                <ul class="toc_section">
                    <li> - <a href="#cotonic.mqtt_bridge.newBridge">newBridge</a>
                    <li> - <a href="#cotonic.mqtt_bridge.newBridge">findBridge</a>
                    <li> - <a href="#cotonic.mqtt_bridge.deleteBridge">deleteBridge</a>
                </ul>
                
                <!-- UI -->
                <a href="#cotonic.ui" class="toc_title">
                    ui
                </a>
                <ul class="toc_section">
                    <li> - <a href="#cotonic.ui.insert">insert</a>
                    <li> - <a href="#cotonic.ui.get">get</a>
                    <li> - <a href="#cotonic.ui.update">update</a>
                    <li> - <a href="#cotonic.ui.remove">remove</a>
                    <li> - <a href="#cotonic.ui.render">render</a>
                    <li> - <a href="#cotonic.ui.renderId">renderId</a>
                    <li> - <a href="#cotonic.ui.updateStateData">updateStateData</a>
                    <li> - <a href="#cotonic.ui.updateStateClass">updateStateClass</a>
                    <li> - <a href="#cotonic.ui.on">on</a>
                </ul>

                <a class="toc_title" href="#cotonic.tokenizer">
                    tokenizer
                </a>
                <ul class="toc_section">
                    <li> - <a href="#cotonic.tokenizer.tokens">tokens</a>
                    <li> - <a href="#cotonic.tokenizer.charref">charref</a>
                </ul>

                <a class="toc_title" href="#worker.functions">
                    Worker Functions
                </a>
                <ul class="toc_section">
                    <li> - <a href="#worker.connect">connect</a>
                    <li> - <a href="#worker.disconnect">disconnect</a>
                    <li> - <a href="#worker.is_connected">is_connected</a>

                    <li> - <a href="#worker.subscribe">subscribe</a>
                    <li> - <a href="#worker.unsubscribe">unsubscribe</a>
                    <li> - <a href="#worker.publish">publish</a>
                    <li> - <a href="#worker.call">call</a>

                    <li> - <a href="#worker.worker_init">worker_init</a>
                    <li> - <a href="#worker.on_connect">on_connect</a>
                    <li> - <a href="#worker.on_error">on_error</a>
                </ul>


                <a class="toc_title" href="#models">
                    Models
                </a>

                <a class="toc_title" href="#model.document">
                    model/document
                </a>
                <ul class="toc_section">
                    <li> - <a href="#model.document.get.all">get/all</a>
                    <li> - <a href="#model.document.get.intl">get/intl</a>
                </ul>

                <a class="toc_title" href="#model.location">
                    model/location
                </a>
                <ul class="toc_section">
                    <li> - <a href="#model.location.get.href">get/href</a>
                    <li> - <a href="#model.location.get.protocol">get/protocol</a>
                    <li> - <a href="#model.location.get.host">get/host</a>
                    <li> - <a href="#model.location.get.hostname">get/hostname</a>
                    <li> - <a href="#model.location.get.hostname">get/origin</a>
                    <li> - <a href="#model.location.get.port">get/port</a>
                    <li> - <a href="#model.location.event.search">event/search</a>
                    <li> - <a href="#model.location.event.pathname">event/pathname</a>
                    <li> - <a href="#model.location.event.hash">event/hash</a>
                    <li> - <a href="#model.location.event.ping">event/ping</a>
                </ul>

                <a class="toc_title" href="#model.ui">
                    model/ui 
                </a>
                <ul class="toc_section">
                    <li> - <a href="#model.ui.insert.key">insert/+key</a>
                    <li> - <a href="#model.ui.update.key">update/+key</a>
                    <li> - <a href="#model.ui.delete.key">delete/+key</a>
                    <li> - <a href="#model.ui.event.recent-activity">event/recent-activity</a>
                    <li> - <a href="#model.ui.event.dom-updated">event/dom-updated/+key</a>
                    <li> - <a href="#model.ui.event.ui-status">event/ui-status</a>
                </ul>

                <a class="toc_title" href="#model.serviceWorker">
                    model/serviceWorker
                </a>
                <ul class="toc_section">
                    <li> - <a href="#model.serviceWorker.post.broadcast.channel">post/broadcast/+channel</a>
                    <li> - <a href="#model.serviceWorker.event.broadcast.channel">event/broadcast/+channel</a>
                    <li> - <a href="#model.serviceWorker.event.ping">event/ping</a>
                </ul>

                <a class="toc_title" href="#model.localStorage">
                    model/localStorage
                </a>
                <ul class="toc_section">
                    <li> - <a href="#model.localStorage.get.key">get/+key</a>
                    <li> - <a href="#model.localStorage.post.key">post/+key</a>
                    <li> - <a href="#model.localStorage.delete.key">delete/+key</a>
                    <li> - <a href="#model.localStorage.event.key">event/+key</a>
                    <li> - <a href="#model.localStorage.event.ping">event/ping</a>
                </ul>

                <a class="toc_title" href="#model.sessionStorage">
                    model/sessionStorage
                </a>
                <ul class="toc_section">
                    <li> - <a href="#model.sessionStorage.get.key">get/+key</a>
                    <li> - <a href="#model.sessionStorage.get.key.subkey">get/+key/+subkey</a>
                    <li> - <a href="#model.sessionStorage.post.key">post/+key</a>
                    <li> - <a href="#model.sessionStorage.post.key.subkey">post/+key/+subkey</a>
                    <li> - <a href="#model.sessionStorage.delete.key">delete/+key</a>
                    <li> - <a href="#model.sessionStorage.delete.key">delete/+key/+subkey</a>
                    <li> - <a href="#model.sessionStorage.event.key">event/+key</a>
                    <li> - <a href="#model.sessionStorage.event.key.subkey">event/+key/+subkey</a>
                    <li> - <a href="#model.sessionStorage.event.ping">event/ping</a>
                </ul>

            </div>

            <div>
                <a class="toc_title" href="#links">Links</a>
            </div>

            <div>
                <a class="toc_title" href="#changelog">Change Log</a>
            </div>
        </section>

        <section id="documentation">

            <p id="introduction">
               <h1 class="logo">COTONIC</h1>
            </p>

            <p>
            <a href="https://github.com/cotonic/cotonic">Cotonic</a> is a Javascript
            library which makes it possible to split the javascript code of your
            page into truly isolated components. By doing this a crash in one component
            can never affect another component.
            </p>

            <p>
            Cotonic provides tools to make it possible for these components to cooperate
            by providing an MQTT publish/subscribe bus. This makes it possible for
            components to communicate via topics.
            </p>

            <p>
            The project is hosted on <a href="https://github.com/cotonic/cotonic">Github</a>.
            You can report bugs and discuss features on the
            <a href="https://github.com/cotonic/cotonic/issues">issues page</a>.
            <p>

            <p>
            Cotonic is an open-source component of <a href="http://zotonic.org">Zotonic</a>.
            </p>

            <h3>Installation</h3>

            Place the <a href="https://cotonic.org/cotonic.js"><tt>cotonic.js</tt></a>,
            <a href="https://cotonic.org/cotonic-worker.js"><tt>cotonic-worker.js</tt></a> and
            <a href="https://cotonic.org/cotonic-service-worker.js"><tt>cotonic-service-worker.js</tt></a> scripts on a web-server.
            (<em>Right-click and use "Safe as"), or use one of the <a href="#changelog">download links</a></em>.

            <br> <br>
            Add the following tag to the page:
            <br> <br>

            <pre>
&lt;script src="//path/to/cotonic.js"
        data-base-worker-src="//path/to/cotonic-worker.js"&gt;&lt;/script&gt;</pre>

            <h2 id="workers">Workers</h2>

            <p>
            Cotonic uses Web Workers which all run in separate calling context. This
            means that they will not block the main user interface thread. They are
            also truly isolated from each other. This means that a crash or another
            kind of problem in worker A can't crash worker B. 
            </p>

            <p>
            You can run whatever code you like in workers, with some exceptions. You
            can't access the DOM, and a lot of things from the window object. This also
            makes them more secure because you don't have to worry that worker code
            from an external resource can steal the a credit-card number entered 
            somewhere in the DOM tree.
            </p>

            <p>
            Cotonic adds a MQTT like publish subscribe mechanism to the standard javascript
            web worker api. This makes it easy for web workers to communicate with each other.
            </p>

<pre>
// worker-a
"use strict";

self.subscribe("some/topic", function(message) {
    self.publish("model/ui/update", "&lt;p&gt;Worker A got message&lt;/p&gt;")
});

self.publish("model/ui/insert", "&lt;p&gt;Worker A started&lt;/p&gt;");</pre>

<pre>
// worker-b
"use strict";

self.subscribe("some/topic", function(message) {
    self.publish("model/ui/update", "&lt;p&gt;Worker B got message&lt;/p&gt;")
});

self.publish("model/ui/insert", "&lt;p&gt;Worker B started&lt;/p&gt;");</pre>


<pre>
let worker_a = cotonic.spawn("worker-a.js", [1, 2]);
let worker_a = cotonic.spawn("worker-b.js");

cotonic.broker.publish("some/topic", "hello workers!");
</pre>

            <h2 id="functions">Page Functions</h2>

            <p>
            Cotonics main functions are available in the <tt>cotonic</tt> namespace on the main page.
            The functions are mostly used to control and allow messaging between workers.
            </p>

            <!-- spawn -->
            <p id="cotonic.spawn">
            <strong class="header">spawn</strong> <code>cotonic.spawn(url, [args])</code>
            <br>
            Spawn a new worker. The code of the worker should be available at <tt>url</tt>. The optional
            <tt>args</tt> parameter list will be passed to the worker and can be used to pass information from
            the page to the worker. It can be picked up with the <a href="#worker.worker_init"><tt>worker_init</tt></a>
            callback. The structured clone algorithm will be used to send the <tt>args</tt> to the worker. See 
            <a href="#worker.functions">worker functions</a> for more information on implementing a worker.
            Returns the worker-id of the newly created worker process.
            </p>
            <pre>
cotonic.spawn("/js/example-worker.js");
=> 1
cotonic.spawn("/js/another-worker.js", ["Arg1", 1]);
=> 2</pre>

            <!-- spawn_named -->
            <p id="cotonic.spawn_named">
            <strong class="header">spawn_named</strong> <code>cotonic.spawn_named(name, src_url, [base], [args])</code>
            <br>
            Spawn a new named worker. Named workers are unique. Use <tt>""</tt> or <tt>undefined</tt> to create a
            nameless worker. Return the worker_id of the newly spawned
            worker. If the worker was already running, the existing worker_id is returned.
            </p>

            <pre>
cotonic.spawn_named("example", "example-worker.js");
=> "worker"</pre>

            <!-- exit -->
            <p id="cotonic.exit">
            <strong class="header">exit</strong> <code>cotonic.exit(nameOrwid)</code>
            <br>
            Exit terminates a worker which was previously spawned and has <tt>nameOrWid</tt> as 
        worker-id.
            </p>

            <pre>
const wid = cotonic.spawn("example.worker.js");
cotonic.exit(wid);
=> Worker <tt>wid</tt> is no longer running.</pre>

            <!-- send -->
            <p id="cotonic.send">
            <strong class="header">send</strong> <code>cotonic.send(nameOrWid, message)</code>
            <br>
            Send message <tt>message</tt> to worker <tt>nameOrWid</tt>. The parameter <tt>nameOrWid</tt>
            can either be the name of worker, or a worker id. The structured clone algorithm will
            be used to copy the <tt>message</tt> before sending it to the worker.
            </p>
            <pre>
cotonic.send(worker_id1, "hello");</pre>

            <!-- receive -->
            <p id="cotonic.receive">
            <strong class="header">receive</strong> <code>cotonic.receive(handler)</code>
            <br>
            Receive messages from workers. The handler should be a function which takes 
            two parameters, the message, and the worker_id.
            </p>
            <pre>
cotonic.receive(function(message, worker_id) {
    console.log("Received", message, "from worker", worker_id);
});</pre>
            
            <!-- set_worker_base_src -->
            <p id="cotonic.set_worker_base_src">
            <strong class="header">set_worker_base_src</strong> <code>cotonic.set_worker_base_src(baseUrl)</code>
            <br>
            Set the base url to load additional importable cotonic modules from. This is used to locate the base
            worker script which is needed to communicate with the other workers. It is usually located in the
            same location as the main cotonic script.
            <br>
            By default the location is <tt>/lib/cotonic/cotonic-worker.js</tt>. It is also possible to 
            configure this via the script via which cotonic itself is loaded on the page.
            <em>Note: When this is not setup correctly, it will not be possible to spawn workers.</em>
            </p>

            <pre>
cotonic.set_worker_base_src("/lib/js/cotonic-worker.js");
=> Cotonic will now use the '/lib/js/cotonic-worker.js' when workers are spawned.</pre>

            <pre>
&ltscript data-worker-base-src="/lib/cotonic-worker.js" src="/lib/cotonic.js"&gt;&lt;/script&gt;
=> Cotonic will use '/lib/cotonic-worker.js' when new workers are spawned.</pre>

            <h3 id="cotonic.broker">Broker</h3>

            <p>
            The broker module handles all local publish subscribe connections. The subscriptions
            are stored in a trie datastructure allowing quick action. They are available in the
            <tt>cotonic.broker</tt> namespace.
            </p>

            <!-- find_subscriptions_below -->
            <p id="cotonic.broker.find_subscriptions_below">
            <strong class="header">find_subscriptions_below</strong> <code>cotonic.broker.find_subscriptions_below(topic)</code>
            <br>
            Find all subscribers below a certain topic. Used by the bridge to collect all subscriptions
            after a session restart. Returns a list with subscriptions.
            </p>
            <pre>
cotonic.broker.find_subscriptions_below("truck");
=> [
  {type: "page", wid: 0, callback: function, sub: Object, topic: "truck/+/speed"}
  {type: "page", wid: 0, callback: function, sub: Object, topic: "#"}]</pre>

            <!-- match -->
            <p id="cotonic.broker.match">
            <strong class="header">match</strong> <code>cotonic.broker.match(topic)</code>
            <br>
            Collect all subscribers which match the topic. Returns a list with subscriptions.
            </p>
            <pre>
cotonic.broker.subscribe("truck/+/speed", function(msg) {
    console.log("Some trucks speed", msg);
});
cotonic.broker.subscribe("truck/#", function(msg) {
    console.log("Some info of a truck", msg);
});
cotonic.broker.subscribe("truck/02/speed", function(msg) {
    console.log("Speed of truck 2", msg);
})

cotonic.broker.match("truck/01/speed");
=> [Object, Object] // Returns two subscriptions, truck/+/speed, and truck/#
cotonic.broker.match("truck/01/speed")[0]
=> {type: "page", wid: 0, callback: function, sub: Object, topic: "truck/+/speed"}  
cotonic.broker.match("truck/02/speed");
=> [Object, Object, Object] // Returns all subscriptions
cotonic.broker.match("boat/02/speed");
=> [] // Has no subscribers</pre>

            <!-- publish -->
            <p id="cotonic.broker.publish">
            <strong class="header">publish</strong> <code>cotonic.broker.publish(topic, payload, [options])</code>
            <br>
            Publish the message <tt>payload</tt> on a topic. The possible <tt>options</tt> are:
            <dl>
                <dt><tt>qos</tt></dt>
                <dd>Quality of service. Can be 0, 1, or 2. 0 means at most once, 1 at least once, and 2 exactly once.</dd>
                <dt><tt>retain</tt></dt>
                <dd>When retain is true, the last message sent will be stored, and delivered immediately when
                a new client subscribes to the topic.</dd>
                <dt><dt>properties</dt></dt>
                <dd>Extra properties which can be attached to the message</dd>
            </dl>
            </p>
            <pre>
cotonic.broker.publish("truck/001/temperature", 88);
=> All subscribers receive the message 88 on the topic.
cotonic.broker.publish("truck/001/speed", 74, {retain: true});
=> All subscribers receive the message 74. New subscribers will immediately receive 74.
            </pre>

            <!-- subscribe -->
            <p id="cotonic.broker.subscribe">
            <strong class="header">subscribe</strong> <code>cotonic.broker.subscribe(topics, callback, [options])</code>
            <br>
            Subscribe to topics. Argument <tt>topics</tt> can either be a single topic, or a list of topics.
            The function <tt>callback</tt> will be called when a message which matches
            one of the topics is published. It is a function is called with two arguments, <tt>message</tt>
            and <tt>info</tt>. Argument <tt>message</tt> is the received mqtt message, and <tt>info</tt>
            the returned information object returned by <a href="#cotonic.mqtt.extract">extract</a>.
            This makes it possible to easily extract information from the topic.
            Parameter <tt>options</tt> can be 
            <dl>
                <dt><tt>wid</tt></dt>
                <dd>The worker if used for making the scription. Can be used to differentiate
                subscriptions from different components on the page. Defaults to: <tt>0</tt></dd>

                <dt><tt>qos</tt></dt>
                <dd>The quality-of-service of the subscription. Defaults to: <tt>0</tt></dd>

                <dt><tt>retain_handling</tt></dt>
                <dd>[todo]</dd>

                <dt><tt>retain_as_published</tt></dt>
                <dd>[todo]</dd>

                <dt><tt>no_local</tt></dt>
                <dd>[todo]</dd>

                <dt><tt>properties</tt></dt>
                <dd>[todo]</dd>
            </dl>
            </p>
            <pre>
cotonic.broker.subscribe("truck/+truck_id/speed",
    function(msg, info) {
         console.log("Truck", info.truckid, "speed:", msg.payload);
    },
    {wid: "example"});
=> The function will now be called when a truck publishes its speed.</pre>

            <!-- unsubscribe -->
            <p id="cotonic.broker.unsubscribe">
            <strong class="header">unsubscribe</strong> <code>cotonic.broker.unsubscribe(topics, [options])</code>
            <br>
            Unsubscribe from the topics. The parameter <tt>topics</tt> can be a single topic as a string,
            or a list of topics. The optional parameter <tt>options</tt> is an object which has the following
            properties.
            <dl>
                <dt>wid</dt>
                <dd>The worker id from which to unsubscribe from. Defaults to: <tt>0</tt></dd>
            </dl>

            </p>
            <pre>
cotonic.broker.unsubscribe("truck/+truck_id/speed",
                           {wid: "example"});
=> The subscriptions for topic "truck/+truck_id/speed" for worker "example" will not be called anymore.
</pre>

            <!-- call -->
            <p id="cotonic.broker.call">
            <strong class="header">call</strong> <code>cotonic.broker.call(topic, payload, [options])</code>
            <br>
            Call is a special kind of publish where the publisher expects an answer back. The <tt>payload</tt>
            will be published on <tt>topic</tt> using the <tt>options</tt> as described in
            <a href="#cotonic.broker.publish">publish</a>.
            The caller will be temporarily subscribed to a reply topic. When an answer is received on this
            reply topic, the returned promise will be resolved. When no answer is received, the promise will
            be rejected with a reason.
            The option parameter can have the following extra options:
            <dl>
                <dt><tt>timeout</tt></dt>
                <dl>
                    The timeout in milliseconds to use before rejecting
                    the returned promise.  Default: <tt>15000</tt>, or
                    15 seconds.
                </dl>
            </dl>
            </p>
            <pre>
cotonic.broker.call("model/localStorage/get/username", {}, {timeout: 1000})
.then(function(username) {
    console.log("The username is:", username");
})
.catch(function(e) {
    console.log("Could not get username within 1 second.", e);
});</pre>

            <h3 id="cotonic.mqtt">MQTT</h3>
            <p>
            The mqtt module provides functions to work with mqtt topics. The <a href="#cotonic.broker">broker</a>
            uses this module as the basis to provide its functionality. This module also has some utility functions
            to easily extract information from topics.
            </p>

            <!-- More info needed, references to MQTT maybe? -->

            <!-- matches -->
            <p id="cotonic.mqtt.matches">
            <strong class="header">matches</strong> <code>cotonic.mqtt.matches(pattern, topic)</code>
            <br>
            Returns <tt>true</tt> when the pattern matches the topic, <tt>false</tt> otherwise.
            </p>
            <pre>
cotonic.mqtt.matches("truck/+/speed", "truck/01/speed");
=> true
cotonic.mqtt.matches("boat/+/speed", "truck/01/speed");
=> false 
cotonic.mqtt.matches("+/+/speed", "plane/01/speed");
=> true 
cotonic.mqtt.matches("+/+/speed", "plane/01/height");
=> false</pre>

            <!-- fill -->
            <p id="cotonic.mqtt.fill">
            <strong class="header">fill</strong> <code>cotonic.mqtt.fill(pattern, params)</code>
            <br>
            Fill can use a <tt>pattern</tt> topic, and use the <tt>param</tt> object to create
            an mqtt topic. Returns a string with the created topic.
            </p>
            <pre>
cotonic.mqtt.fill("truck/+truck_id/speed", {truck_id: 100});
=> "truck/100/speed"</pre>

            <!-- extract -->
            <p id="cotonic.mqtt.extract">
            <strong class="header">extract</strong> <code>cotonic.mqtt.extract(pattern, topic)</code>
            <br>
            Extract values from <tt>topic</tt> into an object. The pattern <tt>+&lt;key&gt;</tt> matches
            a single level of the topic path. It places an attribute <tt>key</tt> with as value the
            found element in the path in the returned object. The pattern <tt>#&ltkey&gt;</tt>
            matches a multi level path. When it is matched it places that part of the path into a list.
            Returns an object with the found elements. 
            </p>
            <pre>
cotonic.mqtt.extract("truck/+truck_id/speed", "truck/01/speed");
=> {truck_id: "01"}
cotonic.mqtt.extract("truck/+truck_id/#params", "truck/01/speed");
=> {truck_id: "01", params: ["speed"]}</pre>

            <!-- exec -->
            <p id="cotonic.mqtt.exec">
            <strong class="header">exec</strong> <code>cotonic.mqtt.exec(pattern, topic)</code>
            <br>
            When the <tt>pattern</tt> <a href="#cotonic.mqtt.matches">matches</a> the <tt>topic</tt>,
            <a href="#cotonic.mqtt.extract">extract</a> the values from the topic. Returns the
            extracted values when the pattern matches, <tt>null</tt> otherwise.</p>
            <pre>
cotonic.mqtt.exec("truck/+truck_id/speed", "truck/01/speed");
=> {truck_id: "01"}
cotonic.mqtt.exec("boat/+truck_id/speed", "truck/01/speed");
=> null</pre>

            <!-- remove_named_wildcards -->
            <p id="cotonic.mqtt.remove_named_wildcards">
            <strong class="header">remove_named_wildcards</strong> <code>cotonic.mqtt.remove_named_wildcards(pattern)</code>
            <br>
            Remove the special, and non mqtt compliant, wildcards from the pattern and return a compliant
            topic.
            </p>
            <pre>
cotonic.mqtt.remove_named_wildcards("truck/+truck_id/speed");
=> "truck/+/speed"
cotonic.mqtt.remove_named_wildcards("truck/#truck_info");
=> "truck/#"</pre>

            <!-- MQTT Bridge -->
            <h3 id="cotonic.mqtt_bridge">mqtt_bridge</h3>
            
            <p>
            This module makes it possible to bridge the broker on the local page to
            an external MQTT broker.
            </p>

            <p id="cotonic.mqtt_bridge.newBridge">
            <strong class="header">newBridge</strong> <code>cotonic.mqtt_bridge.newBridge([remote], [options])</code>
            <br>
            Create a new bridge. This is the hostname of the mqtt broker to connect to. When set to
            <tt>"origin"</tt> the bridge uses the hostname of the document.
            When the bridge is connected messages published on the topic matching <tt>bridge/+remote/#</tt> will
            be re-published on the remote broker. Subscriptions on the topic <tt>bridge/+remote/#</tt>
            will be published locally. This makes it possible to connect and communicate with
            all clients connected to remote mqtt brokers.
            <em>Note: It is possible to connect to multiple brokers.</em>
            <dl>
                <dt><tt>protocol</tt></dt>
                <dd>The protocol to use to connect to the mqtt broker. Defaults to "ws" when the page is 
                loaded via "http", "wss" otherwise.
                </dd>

                <dt><tt>controller_path</tt></dt>
                <dd>The pathname to use when connecting the web socket to the broker. Default: "mqtt-transport"</dd>

                <dt><tt>connect_delay</tt></dt>
                <dd>Default: 20</dd>

                <dt><tt>periodic_delay</tt></dt>
                <dd>Default: 1000</dd>

                <dt><tt>mqtt_session</tt></dt>
                <dd>The mqtt_session module which should be used. Default: cotonic.mqtt_session.</dd>
            </dl>
            </p>
            <pre>
cotonic.mqtt_bridge.newBridge("test.mosquitto.org:8081",
                              {protocol: "wss"});
=> Connect the local broker to test.mosquitto.org via a websocket.

const decoder = new TextDecoder("utf-8");
cotonic.broker.subscribe("bridge/test.mosquitto.org:8081/bbc/subtitles/bbc_news24/raw",
    function(m, t) {
        console.log(decoder.decode(m.payload));
    });
=> Subscribe to a local topic, it will be bridged from the server
   to the page. This gets the raw subtitles of bbc news24.</pre>

            <p id="cotonic.mqtt_bridge.findBridge">
            <strong class="header">findBridge</strong> <code>cotonic.mqtt_bridge.findBridge([remote])</code>
            <br>
            Find bridge <tt>remote</tt>, when remote is not specified, <tt>"origin"</tt> is used.
            Returns the bridge, or <tt>undefined</tt> when the bridge is not found.
            </p>
            <pre>
const b = cotonic.mqtt_bridge.findBridge("test.mosquitto.org:8081");
=> returns the bridge, or undefined
            </pre>

            <p id="cotonic.mqtt_bridge.deleteBridge">
            <strong class="header">deleteBridge</strong> <code>cotonic.mqtt_bridge.deleteBridge([remote])</code>
            <br>
            Delete bridge <tt>remote</tt>, when remote is not specified, <tt>"origin"</tt> is used.
            </p>
            <pre>
cotonic.mqtt_bridge.deleteBridge("test.mosquitto.org:8081");</pre>

            <!-- [TODO] document bridge api -->


            <!-- User interface composer -->

            <h3 id="cotonic.ui">ui</h3>

            <p>
            The user interface composer manages html snippets which can be placed in the DOM tree. When an 
            updated html snippet is delivered to the composer it will render it by using Google's incremental-dom library.
            The updates will be applied <em>incrementally</em> directly to the DOM tree. The updates can be
            delivered as html text snippets to the interface composer.
            </p>

            <!-- insert -->
            <p id="cotonic.ui.insert">
            <strong class="header">insert</strong> <code>cotonic.ui.insert(targetId, isInner, initialHTML, [priority])</code>
            <br>
            Insert a new html snippet into the user interface composer. The snippet will be stored under the given
            targetId. The element will not be placed in the dom-tree immediately. This will happen when one of the 
            render functions is called. The isInner boolean flag indicates if only innerHTML of the target element must
            be updated, or the outerHTML. The optional priority parameter indicates the render order of the elements.
            Elements with a high priority are rendedered before lower priorities. This makes it possible to nest
            elements.
            </p>
            <pre>
cotonic.ui.insert("root", false, "&lt;p&gt;Hello World!&lt;/p&gt;");</pre>

            <!-- get -->
            <p id="cotonic.ui.get">
            <strong class="header">get</strong> <code>cotonic.ui.get(id)</code>
            <br>
            Returns the current html snippet registered at <tt>id</tt>.
            </p>
            <pre>
let currentHTML = cotonic.ui.get("root");
=> "<a href='example.com'>Hello World!</a>"</pre>

            <!-- remove -->
            <p id="cotonic.ui.remove">
            <strong class="header">remove</strong> <code>cotonic.ui.remove(id)</code>
            <br>
            Remove the html snippet registered at id. Note that this will not remove the element from the dom-tree,
            it will only remove it from the user interface composer. When the element must be removed it should first
            be updated and set to a blank string and a render operation should be done.
            </p>
            <pre>
cotonic.ui.remove("root");</pre>

            <!-- update -->
            <p id="cotonic.ui.update">
            <strong class="header">update</strong> <code>cotonic.ui.update(id, htmlOrTokens)</code>
            <br>
            Update the registered snippet for the registered element with the given id. The new snippet will be visible
            after a render operation.
            </p>
            <pre>
cotonic.ui.update("root", "&lt;p&gt;Hello Everybody!&lt;/p&gt;");
=> The root element on the page will be updated.</pre>

            <!-- render -->
            <p id="cotonic.ui.render">
            <strong class="header">render</strong> <code>cotonic.ui.render()</code>
            <br>
            Trigger a render of all registered elements.
            </p>
            <pre>
cotonic.ui.render();
=> All elements will be (re)rendered.</pre>

            <!-- renderId -->
            <p id="cotonic.ui.renderId">
            <strong class="header">renderId</strong> <code>cotonic.ui.renderId(id)</code>
            <br>
            Just render the element with the given id.
            </p>
            <pre>
cotonic.ui.renderId("root");</pre>

            <!-- updateStateData -->
            <p id="cotonic.ui.updateStateData">
            <strong class="header">updateStateData</strong> <code>cotonic.ui.updateStateData(model, states)</code>
            <br>
            Communicate the state of the model to other non-cotonic components on the page. It can
            be used to pass model state to SPA's or other modules. It sets a data attribute on the
            html tag of the page.
            The parameter <tt>model</tt> should be a string, <tt>states</tt> is an object
            with values. The values of the states object are set as data attributes
            on the html tag like this:
            <tt>data-ui-&lt;model&gt;-&lt;key&gt;="&lt;value&gt;"</tt>. When an empty object is
            passed all data attributes of the model is cleared.
            </p>
            <pre>
cotonic.ui.updateStateData("auth", {authorized: true});
=> &lt;html data-ui-state-auth-authorized="true"&gt;
...
cotonic.ui.updateStateData("auth", {});
=> &lt;html"&gt;
...</pre>

            <!-- updateStateClass -->
            <p id="cotonic.ui.updateStateClass">
            <strong class="header">updateStateClass</strong> <code>cotonic.ui.updateStateClass(model, classes)</code>
            <br>
            Update the class of the html tag. This makes it possible to communicate important
            state changes to external components like SPA's. The parameter <tt>model</tt> should be
            a string. Parameter <tt>classes</tt> a list of classes which must be set.
            The following elements will be added to the class attribute
            <tt>ui-state-&lt;model&gt;-&lt;class&gt;</tt>. Passing <tt>[]</tt> will clear all the class
            attributes of the model.
            </p>
            <pre>
cotonic.ui.updateStateClass("auth", ["unauthorized", "pending"]);
=> &lt;html class="ui-state-auth-pending ui-state-auth-unauthorized"&gt; 
cotonic.ui.updateStateClass("auth", ["authorized"]);
=> &lt;html class="ui-state-auth-authorized"&gt;</pre>

            <!-- on -->
            <p id="cotonic.ui.on">
            <strong class="header">on</strong> <code>cotonic.ui.on(topic, msg, event, [options])</code>
            <br>
            Publish a DOM event on the local broker. This allows subscribers to react to user interface
            events. Parameter <tt>topic</tt> is the topic on which the event will be published. The parameters
            <tt>msg</tt> and <tt>event</tt> are included in the message which is published. The event parameter
            is expected to be a DOM event. The <tt>options</tt> parameter is optional, it
            can contain a <tt>cancel</tt> property which can be set to <tt>true</tt>, <tt>false</tt> or
            <tt>"preventDefault"</tt> to indicate if the event should be cancelled or prevented.
            The other options can be the normal options found in
            <a href="#cotonic.broker.publish"><tt>publish</tt></a>.
            </p>
            <pre>
document.addEvenListener("click", function(e) {
    const topic = event.target.getAttribute("data-topic");
    if(!topic) return;
    
    cotonic.ui.on(topic, {foo: "bar"}, e);
}, {passive: true})
=> When somebody clicks on an element with has a data-topic="a/topic"
   attribute, the event will be published on that topic.</pre>

            <h3 id="cotonic.tokenizer">tokenizer</h3>

            <p>
            The tokenizer transforms text to html tokens. The tokenizer is used by the
            user interface composer in order to call the incremental-dom api.
            It uses incremental-dom to do in-place diffing of the dom-tree.
            <br>
            <em>Note: The tokenizer does not parse or validate the html. It just
                tokenizes the input.</em>

            </p>

            <!-- tokens -->
            <p id="cotonic.tokenizer.tokens">
            <strong class="header">tokens</strong> <code>cotonic.tokenizer.tokens(text)</code>
            <br>
            Transforms a string with html tags into a list of tokens. The tokens are
            objects of the form: <tt>{type: "type", [args]}</tt>, with type being one of:
            <dl>
                <dt><tt>open</tt><dt>
                <dd>Represents an open tag. Contains the attribute <tt>tag</tt> which is
                set to the tagname of the element, and the attribute <tt>attributes</tt>
                which is a list of attributes of the element.
                </dd>

                <dt><tt>close</tt><dt>
                <dd>Represents a close tag. Contains the attribute <tt>tag</tt> which is
                set to the tagname of the close element.</dd>

                <dt><tt>void</tt><dt>
                <dd>Represents a void element. The attribute <tt>tag</tt> is set to the 
                tagname of the void element.</dd>

                <dt><tt>text</tt><dt>
                <dd>Represents a test element. The attribute <tt>data</tt> is set to the
                text data.</dd>

                <dt><tt>doctype</tt><dt>
                <dd>Represents a doctype element. The attribute <tt>attributes</tt> is 
                set to the attributes of the element.</dd>

                <dt><tt>pi</tt><dt>
                <dd>Represents a processing instruction element. The attribute <tt>tag</tt>
                is set to the tagname of the processing instruction. The attribute
                <tt>arguments</tt> contains the list of attributes.</dd>

                <dt><tt>comment</tt><dt>
                <dd>Represents a comment element. The attribute <tt>data</tt> contains 
                the text in the comment element.</dd>
            </dl>
            </p>
            <pre>
cotonic.tokenizer.tokens("&lt;div class='example'&gt;Tokenizing&lt;br /&gt; is cool&lt/div&gt;");
=> [{type: "open", tag: "div", attributes: ["class", "example"]},
    {type: "text", data: "Tokenizing"},
    {type: "void", tag: "br", attributes: []},
    {type: "text", data: " is cool"},
    {type: "close", tag: "div"}] </pre>

            <!-- charref -->
            <p id="cotonic.tokenizer.charref">
            <strong class="header">charref</strong> <code>cotonic.tokenizer.charref(text)</code>
            <br>
            Transforms a html charref into a character.
            </p>
            <pre>
cotonic.tokenizer.charref("#128540");
=> "😜" 
cotonic.tokenizer.charref("amp");
=> "&"</pre>



            <h2 id="worker.functions">Worker Functions</h2>
            <p>
            Workers are stand alone processes. They have no shared data with the page, nor
            with other workers. Their memory and calling context is isolated. They can easily communicate
            with other workers, the page, and servers by publising messages on topics, and subscribing
            to them. Cotonic provides <a href="#models">models</a>, modules which are loaded and
            ready for requests.
            </p>

            <!-- worker connect -->
            <p id="worker.connect">
            <strong class="header">connect</strong> <code>self.connect()</code>
            <br>
            Connect the worker to the page. When this step succeeds the
            <a href="#worker.on_connect"><tt>on_connect</tt></a> is called.
            <a href="#worker.on_error"><tt>on_error</tt></a> when it fails.
            </p>
            <pre>
self.connect();
=> The worker is being connected to the page.</pre>

            <!-- worker disconnect -->
            <p id="worker.disconnect">
            <strong class="header">disconnect</strong> <code>self.disconnect()</code>
            <br>
            Disconnects the worker from the page. After this step it is no
            longer possible to send and receive messages from the page.
            </p>
            <pre>
self.disconnect();
=> The worker is disconnected from the page.</pre>

            <!-- worker is_connected -->
            <p id="worker.is_connected">
            <strong class="header">is_connected</strong> <code>self.is_connected()</code>
            <br>
            Returns <tt>true</tt> iff the worker is connected to the page,
            <tt>false</tt> otherwise.
            </p>
            <pre>
self.is_connected();
=> true</pre>

            <!-- worker subscribe -->
            <p id="worker.subscribe">
            <strong class="header">subscribe</strong> <code>self.subscribe(topics, callback, ack_callback)</code>
            <br>
            Subscribe the worker to the <tt>topics</tt>. When a message is received, the <tt>callback</tt> is called.
            Callback is a function which receives two parameters. The first parameter is the <tt>message</tt>, the second
            parameter an <tt>object</tt> returned by <a href="#cotonic.mqtt.extract">extract</a>. This can be used to
            easily extract elements from topic paths in an object. The parameter <tt>topics</tt> can be a string, or
            a list of strings. The callback <tt>ack_callback</tt> is used when the page is subscribed, or when
            there is a problem. Returns nothing.
            </p>
            <pre>
function logSpeed(msg, args) {
    if(args.boat_id) {
        console.log("boat", args.boat_id, "is now moving at", msg.payload);
    }
    if(args.truck_id) {
        console.log("truck", args.truck_id, "is now moving at", msg.payload);
    }
}
self.subscribe(["truck/+boat_id/speed", "boat/+boat_id/speed"], logSpeed);
=> The function logSpeed will be called when somebody sends a message which
   matches the topics.</pre>

            <!-- worker unsubscribe -->
            <p id="worker.unsubscribe">
            <strong class="header">unsubscribe</strong> <code>self.unsubscribe(topics, callback, ack_callback)</code>
            <br>
            Unsubscribe the worker from page. The worker will no longer receive messages from the specified topics. 
            </p>
            <pre>
self.unsubscribe();</pre>

            <!-- worker publish -->
            <p id="worker.publish">
            <strong class="header">publish</strong> <code>self.publish(topic, message, options)</code>
            <br>
            Publish <tt>message</tt> on <tt>topic</tt>. The <tt>options</tt> can be used to indicate
            the quality of service, or if the message should be retained by the broker.
            </p>
            <pre>
self.publish("world", "hello", {retain: true});</pre>

            <!-- worker call -->
            <p id="worker.call">
            <strong class="header">call</strong> <code>self.call(topic, message, options)</code>
            <br>
            Publishes <tt>message</tt> on <tt>topic</tt> and subscribes itself to a reply topic.
            Returns a promise which is fulfilled when a message is received on the reply topic. When
            no message arrives, the promise is rejected. Returns a promise.
            </p>
            <pre>
self.call("model/document/get/all")
.then(...)
.reject(...);</pre>

            <!-- worker worker_init-->
            <p id="worker.worker_init">
            <strong class="header">worker_init</strong> <code>self.worker_init</code>
            <br>
            The callback <tt>worker_init</tt> is called when the worker receives the initialization
            message by the page. It can take multiple arguments. The arguments are passed in via
            the <a href="#cotonic.spawn"><tt>spawn</tt></a> <tt>args</tt> argument list. 
            This function can be used to initialize the worker, but it is optional.
            </p>
            <pre>
// Worker code

let amount = null;
let targetId = null;

self.worker_init = function(n, id) {
    amount = n; 
    targetId = id;
}</pre>

            <!-- worker on_connect -->
            <p id="worker.on_connect">
            <strong class="header">on_connect</strong> <code>self.on_connect</code>
            <br>
            The <tt>on_connect</tt> callback will be called after a successfull
            <a href="#worker.connect"><tt>connect</tt></a> call.
            </p>
            <pre>
self.on_connect = function() {
    // things to do after a connect
}</pre>

            <!-- worker on_error -->
            <p id="worker.on_error">
            <strong class="header">on_error</strong> <code>self.on_error</code>
            <br>
            The <tt>on_error</tt> callback will be called after an unsuccessfull
            <a href="#worker.connect"><tt>connect</tt></a> call.
            </p>
            <pre>
self.on_error = function() {
    // things to do after an error
}</pre>

            <h2 id="models">Models</h2>

            <p>
            Because workers run as independent components it is not possible to directly
            call api's. Some api's are also not available to web workers. Models are 
            special modules, or workers, which publish their data, or are ready to 
            receive calls via mqtt topics.
            </p>

            <p>
            The convention is that models provide their services via the following topic
            tree.

            <dl>
                <dt><tt>model/+modelName/get/+</tt></dt>
                <dd>Call topics. When the model receives a publish, it returns the answer
                to the reply topic.</dd>

                <dt><tt>model/+modelName/post/+</tt></dt>
                <dd>Topics used to post updates to the model.</dd>

                <dt><tt>model/+modelName/delete/+</tt></dt>
                <dd>Topics used to delete items managed by the model.</dd>

                <dt><tt>model/+modelName/event/+</tt></dt>
                <dd>Topics which the model publishes events on.</dd>
            </dl>

            </p>

            <!-- model document -->
            <h3 id="model.document">model/document</h3>
            <p>
            The document model can be used to retrieve details about the current document.
            </p>

            <!-- get/all -->
            <p id="model.document.get.all">
            <strong class="header">get/all</strong>
            <br>
            Get all information on the current document. Includes screen size, cookies, user agent details.
            </p>
            <pre>
self.call("model/document/get/all")
.then(function(m) {
    console.log(m.payload)
});
=> {screen_width: 1280, screen_height: 800,
    inner_width: 1047, inner_height: 292,
    is_touch: false, …}</pre>

            <!-- get/intl -->
            <p id="model.document.get.intl">
            <strong class="header">get/intl</strong>
            <br>
            Returns the internationalization details of the current page.
            </p>
            <pre>
self.call("model/document/get/intl")
.then(function(m) {
    console.log(m.payload)
});
=>  {timezone: {cookie: "", user_agent: "Europe/Amsterdam"},
     language: {cookie: "", user_agent: "en-US", document: null}}</pre>

            <!-- model location -->
            <h3 id="model.location">Location</h3>
            <p>
            The location model can be used to retrieve information on the current location
            of the page. It also allows subscription to location changes.
            </p>

            <!-- get/href -->
            <p id="model.location.get.href">
            <strong class="header">get/href</strong>
            <br>
            Get the current href.
            </p>
            <pre>
self.call("model/location/get/href")
.then(function(m) {
    console.log(m.payload)
});
=> "https://cotonic.org/#model.location"</pre>

            <!-- get/protocol -->
            <p id="model.location.get.protocol">
            <strong class="header">get/protocol</strong>
            <br>
            Get the current protocol
            </p>
            <pre>
self.call("model/location/get/protocol")
.then(function(m) {
    console.log(m.payload)
});
=> "https"</pre>

            <!-- get/host -->
            <p id="model.location.get.host">
            <strong class="header">get/host</strong>
            <br>
            Get the current host (with port).
            </p>
            <pre>
self.call("model/location/get/host")
.then(function(m) {
    console.log(m.payload)
});
=> "cotonic.org"</pre>

            <!-- get/hostname -->
            <p id="model.location.get.hostname">
            <strong class="header">get/hostname</strong>
            <br>
            </p>
            Get the current hostname (without port).
            <pre>
self.call("model/location/get/hostname")
.then(function(m) {
    console.log(m.payload)
});
=> "cotonic.org"</pre>

            <!-- get/origin -->
            <p id="model.location.get.origin">
            <strong class="header">get/origin</strong>
            <br>
            Get the current origin.
            </p>
            <pre>
self.call("model/location/get/origin")
.then(function(m) {
    console.log(m.payload)
});
=> "https://cotonic.org"</pre>

            <!-- get/pathname -->
            <p id="model.location.get.pathname">
            <strong class="header">get/pathname</strong>
            <br>
            Get the current pathname.
            </p>
            <pre>
self.call("model/location/get/pathname")
.then(function(m) {
    console.log(m.payload)
});
=> "/"</pre>

            <!-- get/port -->
            <p id="model.location.get.port">
            <strong class="header">get/port</strong>
            <br>
            Get the current port.
            </p>
            <pre>
cotonic.broker.call("model/location/get/port")
.then(function(m) {
    console.log(m.payload)
})
=> "" // The default port.</pre>

            <!-- event/search -->
            <p id="model.location.event.search">
            <strong class="header">event/search</strong>
            <br>
            A message containing the query string part of the url will be published when it changes.
            <em>Note: the message is retained</em>
            </p>
            <pre>
cotonic.broker.subscribe("model/location/event/search",
    function(m, a) {
        console.log("query string changed", m.payload);
});</pre>

            <!-- event/pathname -->
            <p id="model.location.event.pathname">
            <strong class="header">event/pathname</strong>
            <br>
            A message containing the pathname part of the url will be published when it changes.
            <em>Note: the message is retained</em>
            </p>
            <pre>
cotonic.broker.subscribe("model/location/event/pathname",
    function(m, a) {
        console.log("pathname changed", m.payload);
    });</pre>

            <!-- event/hash -->
            <p id="model.location.event.hash">
            <strong class="header">event/hash</strong>
            <br>
            A message containing the hash part of the url will be published when it changes.
            <em>Note: the message is retained</em>
            </p>
            <pre>
cotonic.broker.subscribe("model/location/event/hash",
    function(m, a) {
        console.log("hash changed", m.payload);
    });</pre>

            <!-- event/ping -->
            <p id="model.location.event.ping">
            <strong class="header">event/ping</strong>
            <br>
            When the location model is enabled, a retained message is published on this
            topic. By subscribing to this topic it is possible to see when the model is
            enabled. The payload of the message <tt>pong</tt>.
            </p>
            <pre>
cotonic.broker.subscribe("model/location/event/ping",
    function(m) { 
        console.log("The location model is enabled", m.payload)
    })
=> Logs a message on the console when the location model is enabled.</pre>


            <h3 id="model.ui">model/ui</h3>

            <p>
            The ui model can be used to update the dom by publishing messages on one of the
            <tt>model/ui/#</tt> topics. Elements can be inserted, deleted and updated. When
            elements in the dom-tree are updated, the a message
            <tt>model/ui/event/dom-updated/+key</tt> is published. This can be used to
            react to dom-changes when they happen.
            </p>

            <p id="model.ui.insert.key">
            <strong class="header">insert/+key</strong>
            <br>
            Insert a new ui snippet named <tt>key</tt> into the user interface composer.
            Expects a message with the following properties.

            <dl>
                <dt><tt>initialData</tt></dt>
                <dd>The initial data to place in the dom tree.</dd>

                <dt><tt>inner</tt></dt>
                <dd>If set to <tt>true</tt>, the ui composer will update the inner html, when set
                to <tt>false</tt>, the outer html</dd>

                <dt><tt>priority</tt></dt>
                <dd>An element with a high priority will be rendered before elements with a low
                priority.
                <!-- needs example -->
                </dd>
            </dl>

            </p>
            <pre>
self.publish("model/ui/insert/root", {
    initialData: "&lt;div class='loading'&gt;Loading&lt;/div&gt;",
    inner: true
    priority: 100
}, {retain: true});
=> When the ui composer receives this message it will add the
   loading
            </pre>

            <p id="model.ui.update.key">
            <strong class="header">update/+key</strong>
            <br>
            Update the contents of ui snippet named <tt>key</tt> previously registered
            by an <tt>insert</tt>. Expects a message with the html snippet as message.
            </p>
            <pre>
self.publish("model/ui/update/root", 
    "<div class="main-app>" +
        "..." +
    "</div>");
=> The root element is updated.</pre>

            <p id="model.ui.delete.key">
            <strong class="header">delete/+key</strong>
            <br>
            Delete ui snippet named <tt>key</tt> from the user interface composer.
            </p>
            <pre>
self.publish("model/ui/delete/root");
=> The root element is removed from the composer, but
   stays in the DOM tree.</pre>

            <p id="model.ui.event.recent-activity">
            <strong class="header">event/recent-activity</strong>
            <br>
            A message containing the user's activity status is published regularly
            on this topic. The message is an object which contains a
            <tt>is_active</tt> boolean property which indicates if the has been
            active over the last period between publishes.
            </p>
            <pre>
// worker example
self.subscribe("model/ui/event/user-activity",
    function(m) {
        const a = m.payload.is_active:"active":"not active";
        console.log("The user is: ", a);
    }
); 
=> Displays the user's activity status.</pre>

            <p id="model.ui.event.dom-updated">
            <strong class="header">event/dom-updated/+key</strong>
            <br>
            When the dom-tree is updated a message will be published. The
            message is fired after the dom-tree is updated.
            </p>
            <pre>
cotonic.broker.subscribe("model/ui/event/dom-updated/message-container",
    function(m) {
        const c = document.getElementById("message-container");
        c.scrollTop = c.scrollHeight
    }
);
=> Scrolls the messages bubble container to the bottom.
            </pre>



            <p id="model.ui.event.ui-status">
            <strong class="header">event/ui-status</strong>
            <br>
            </p>
            <pre></pre>



            <!-- serviceWorker model -->
            <h3 id="model.serviceWorker">model/serviceWorker</h3>

            <p>
            The serviceWorker model makes it possible to communicate with other tabs
            from the same site. This makes it possible to communicate important state
            to all tabs.
            </p>

            <div class="note">
                <p>
                <strong class="header">A Note on Security</strong>
                <br>
                The serviceWorker needs https to work correctly. The <i>Chrome</i> browser
                does not accept self-signed certificates for running serviceWorkers.
                Either run from localhost, use a real certificate, or follow the instructions
                <a href="https://deanhume.com/testing-service-workers-locally-with-self-signed-certificates/" target="_blank">on this page by Dean Hume</a>.
                </p>

                <p>
                Safari and Firefox accept self-signed certificates for
                running the serviceWorker.
                </p>
            </div>

            <p id="model.serviceWorker.post.broadcast.channel">
            <strong class="header">post/broadcast/+channel</strong>
            <br>
            Broadcast the message on <tt>channel</tt>. The message can be received 
            via the <tt>"model/serviceWorker/event/+channel</tt> topic. This works
            across all open tabs. 
            </p>
            <pre>
// Publish from a worker
self.publish("model/serviceWorker/post/broadcast/background",
             {hue: "blue", brightness: 45});
            </pre>

            <p id="model.serviceWorker.event.broadcast.channel">
            <strong class="header">event/broadcast/+channel</strong>
            <br>
            Subscribe to the broadcast <tt>channel</tt> of the serviceWorker. Messages
            posted from other tabs or workers, including messages sent by the publisher
            will be received.
            </p>
            <pre>
// Subscribe on a page
cotonic.broker.subscribe("model/serviceWorker/event/broadcast/background",
    function(m) {
        console.log("Setting background to", m.payload");
        setBackground(m.payload);
    })</pre>

            <p id="model.serviceWorker.event.ping">
            <strong class="header">event/ping</strong>
            <br>
            When the serviceWorker model is enabled it publishes a retained <tt>pong</tt>
            message on this topic. This makes it possible to check if the model is enabled.
            </p>
            <pre>
// Subscribe on a page            
cotonic.broker.subscribe("model/serviceWorker/event/ping",
    function() {
        console.log("the serviceWorker model is enabled")
   });</pre>

            <h3 id="model.localStorage">model/localStorage</h3>

            <p id="model.localStorage.get.key">
            <strong class="header">get/+key</strong>
            <br>
            Gets item <tt>key</tt> from localStorage. Returns the content as payload.
            </p>
            <pre>
cotonic.broker.call("model/localStorage/get/a")
.then(
    function(m) {
        console.log("a is set to:", m.payload)
    }
);</pre>

            <p id="model.localStorage.post.key">
            <strong class="header">post/+key</strong>
            <br>
            Update, or insert message under <tt>key</tt> in localStorage.
            </p>
            <pre>
cotonic.broker.publish("model/localStorage/post/a", "Hello world!");</pre>

            <p id="model.localStorage.delete.key">
            <strong class="header">delete/+key</strong>
            <br>
            Delete item stored under <tt>key</tt> from localStorage.
            </p>
            <pre>
cotonic.broker.publish("model/localStorage/delete/a");</pre>

            <p id="model.localStorage.event.key">
            <strong class="header">event/+key</strong>
            <br>
            Subscribe to changes or deletions from localStorage. When the message payload
            is <tt>null</tt> the item is delete. Otherwise the payload is set to the 
            newly updated value.
            </p>
            <pre>
cotonic.broker.subscribe("model/localStorage/event/+key",
    function(m, a) {
        if(m.payload === null) {
            console.log("localStorage item:", a.key, "deleted");
        else {
            console.log("localStorage item:", a.key, "changed", m.payload);
        }
    });
=> Logs update to localStorage elements.</pre>

            <p id="model.localStorage.event.ping">
            <strong class="header">event/ping</strong>
            <br>
            When the localStorage model is enabled it publishes a retained message
            under the topic <tt>model/localStorage/event/ping</tt>. It makes it 
            possible to detect the localStorage model is enabled.
            </p>
            <pre>
cotonic.broker.subscribe("model/localStorage/event/ping",
    function() {
        console.log("localStorage is enabled");
    });</pre>

            <h3 id="model.sessionStorage">model.sessionStorage</h3>
            <p>
            The sessionStorage model provids access to the <tt>sessionStorage</tt> of
            the browser. It makes it possible to set and retrieve values via 
            mqtt topics. For more information about the session storage see: 
            </p>

            <p id="model.sessionStorage.get.key">
            <strong class="header">get/+key</strong>
            <br>
            Get the element stored as <tt>key</tt> from the sessionStorage. Returns the
            contents as payload, or <tt>null</tt> if it is not found.
            </p>
            <pre>
self.call("model/sessionStorage/get/item-1")
.then(function(m) {
    console.log("item-1", m.payload);
});
=> Logs the item-1 on the console, or null otherwise.
           </pre>

            <p id="model.sessionStorage.get.key.subkey">
            <strong class="header">get/+key/+subkey</strong>
            <br>
            Get a sub element stored as <tt>key.subkey</tt> from the sessionStorage.
            </p>
            <pre>
self.call("model/sessionStorage/get/item-2/a")
.then(function(m) {
    console.log("item-2", m.payload);
});
=> Logs the item-2 on the console, or null otherwise.</pre>

            <p id="model.sessionStorage.post.key">
            <strong class="header">post/+key</strong>
            Store a message under <tt>key</tt> in the sessionStorage.
            </p>
            <pre>
self.publish("model/sessionStorage/post/item-1", "Cucumbers are sometimes green");            
=> New value stored.</pre>

            <p id="model.sessionStorage.post.key.subkey">
            <strong class="header">post/+key/+subkey</strong>
            <br>
            Store a message under <tt>key.subkey</tt> in the sessionStorage. When no
            item is stored under <tt>key</tt> a new object is created, and <tt>subkey</tt>
            is added as sub-element. When <tt>key</tt> exists it must be an object, then
            <tt>subkey</tt> is added or overwritten.
            </p>
            <pre>
self.publish("model/sessionStorage/post/item-2/a", "hello");</pre>

            <p id="model.sessionStorage.delete.key">
            <strong class="header">delete/+key</strong>
            <br>
            Delete an element stored under <tt>key</tt> from the sessionStorage.
            </p>
            <pre>
self.publish("model/sessionStorage/delete/item-2");</pre>

            <p id="model.sessionStorage.delete.key.subkey">
            <strong class="header">delete/+key/+subkey</strong>
            <br>
            Delete an element stored under <tt>key.subkey</tt> from the sessionStorage.
            </p>
            <pre>
self.publish("model/sessionStorage/delete/item-2");</pre>

            <p id="model.sessionStorage.event.key">
            <strong class="header">event/+key</strong>
            <br>
            Subscribe to sessionStorage updates and deletes. When entry is updated
            you will get a notification.
            </p>
            <pre>
self.subscribe("model/sessionStorage/subscribe/+key",
    function(m, a) {
        console.log(m, a);
    });
self.publish("model/sessionStorage/post/a", "hello");            
self.publish("model/sessionStorage/post/b", "world");            
=> Logs the update in the console</pre>

            <p id="model.sessionStorage.event.ping">
            <strong class="header">event/ping</strong>
            <br>
            When the sessionStorage model is enabled a retained message is published
            on the <tt>model/sessionStorage/event/ping</tt> topic.
            </p>
            <pre>
let storageReady = false;
cotonic.broker.subscribe("model/sessionStorage/event/+key",
    function(msg, args) {
        switch(args.key) 
        case "pong": 
            storageReady = true;
            break;
        ...
    });
=> When the storage is ready a pong message will be available</pre>

            <h3 id="links">Links</h3>

            <p>
               <a href="https://medium.com/google-developers/introducing-incremental-dom-e98f79ce2c5f">Introduction to Incremental DOM</a>
            </p>

            <p>
               <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html">MQTT Version 5.0 - OASIS</a>
            </p>

            <p>
                <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">Web Workers API</a>
            </p>

            <p>
               <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage">sessionStorage API</a>
            </p>

            <h3 id="changelog">Change Log</h3>

            <p id="1.0.3">
            <strong class="header">1.0.3</strong> &mdash; <small><i>Mar 1, 2020</i></small> &mdash;
            <a href="https://github.com/cotonic/cotonic/compare/1.0.2...1.0.3">Diff</a> &mdash;
            <a href="https://ghcdn.rawgit.org/cotonic/cotonic/1.0.3/index.html"l>Docs</a> &mdash;
            <a href="https://github.com/cotonic/cotonic/archive/1.0.3.tar.gz" download>Download</a>
            <br />
            <ul>
                <li>
                    Added more documentation and an example.
                </li>
                <li>
                    Load the base worker library via a standard importScripts, instead of url blob.
                </li>
                <li>
                    The bridge now supports connecting to any MQTT server.
                </li>
                <li>
                    Removed the embedded polyfills, and use an external polyfill provider when needed.
                    Mostly for IE11.
                </li>
            </ul>
            </p>


            <p id="1.0.2">
            <strong class="header">1.0.2</strong> &mdash; <small><i>Feb 10, 2020</i></small> &mdash;
            <a href="https://github.com/cotonic/cotonic/compare/1.0.1...1.0.2">Diff</a> &mdash;
            <a href="https://ghcdn.rawgit.org/cotonic/cotonic/1.0.2/index.html"l>Docs</a> &mdash;
            <a href="https://github.com/cotonic/cotonic/archive/1.0.2.tar.gz" download>Download</a>
            <br />
            <ul>
                <li>
                    Added documentation, and
                </li>
                <li>
                    made it possible to use the bridge to connect to mqtt servers
                </li>
            </ul>
            </p>

            <p id="1.0.1">
            <strong class="header">1.0.1</strong> &mdash; <small><i>Jan 30, 2020</i></small> &mdash;
            <a href="https://github.com/cotonic/cotonic/compare/1.0.0...1.0.1">Diff</a> &mdash;
            <a href="https://ghcdn.rawgit.org/cotonic/cotonic/1.0.1/index.html"l>Docs</a> &mdash;
            <a href="https://github.com/cotonic/cotonic/archive/1.0.1.tar.gz" download>Download</a>
            <br />
            <ul>
                <li>
                    Fixed all the tests, and
                </li>
                <li>
                    made the documentation more readable on mobile.
                </li>
            </ul>
            </p>

            <p id="1.0.0">
            <strong class="header">1.0.0</strong> &mdash; <small><i>Jan 23, 2020</i></small> &mdash;
            <a href="https://ghcdn.rawgit.org/cotonic/cotonic/1.0.0/index.html">Docs</a> &mdash;
            <a href="https://github.com/cotonic/cotonic/archive/1.0.0.tar.gz" download>Download</a>
            <br />
            <ul>
                <li>
                    First Release!
                </li>
            </ul>
            </p>

        </section>

        <!-- Load cotonic to be able to play with it in the console -->
        <script type="text/javascript" src="/cotonic.js"
                data-base-worker-src="/cotonic-worker.js"></script>
        <script>
            console.log("Welcome to COTONIC. You can try the api in the console");
            console.log("------------------------------------------------------");
            console.log("You can start an example worker by calling");
            console.log("cotonic.spawn(\"/examples/empty-worker.js\")");
            console.log("With the console you can select the calling");
            console.log("context of the worker and run the examples found here.");
        </script>

    </body>
</html>
